# DiscScreen - This screen allows user to browse and play tracks from CD album.
# Copyright (C) 2007 Lauri Taimila
# 
# Entertainer is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
# 
# Entertainer is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

__licence__ = "GPLv2"
__copyright__ = "2007, Lauri Taimila"
__author__ = "Lauri Taimila <lauri@taimila.com>"

import os
import gtk
import time
import pango
import thread
import gobject
import clutter

from frontend.user_event import UserEvent
from frontend.gui.screens.screen import Screen
from utils.albumart_downloader import AlbumArtDownloader
from frontend.gui.transitions.transition import Transition

# Widgets
from frontend.gui.widgets.text_menu import TextMenu
from frontend.gui.widgets.loading_animation import LoadingAnimation
from frontend.gui.widgets.text_menu_item import TextMenuItem
from frontend.gui.widgets.list_indicator import ListIndicator
from frontend.gui.widgets.eyecandy_texture import EyeCandyTexture

# Music library
from frontend.medialibrary.playlist import Playlist
from frontend.medialibrary.music import CompactDisc
from frontend.medialibrary.music import MusicLibrary
from frontend.medialibrary.music import CompactDiscTrack

class DiscScreen(Screen):
    """
    DiscScreen
    
    Screen that allows user to browse and play tracks from the current Audio CD.
    """
    
    def __init__(self, ui, frontend):
        """
        Initialize screen
        
        @param ui: UserInterface object
        @param frontend: FrontendClient object
        @param album: Album object (We display information of this album)
        """
        self.group = clutter.Group()
        Screen.__init__(self, ui.STAGE_WIDTH, ui.STAGE_HEIGHT)
        
        self.ui = ui
        self.frontend = frontend
        self.theme = frontend.getTheme()
        self.library = self.frontend.get_music_library()
        self.player = self.ui.get_media_player()
        self.playlist = None # When album info is loaded we create Playlist object
        
        # Screen Title (Displayed at the bottom left corner)
        screen_title = clutter.Label()
        screen_title.set_font_name(self.theme.getFont() + " " + str(self.ui.y(0.13)) + "px")
        screen_title.set_color(self.theme.getColor("screentitle"))
        screen_title.set_text("Audio Disc")
        screen_title.set_name("screen_title")
        screen_title.set_position(self.ui.x(0), self.ui.y(0.87))
        screen_title.show()
        self.group.add(screen_title)
        
        # Display throbber animation while loading CD metadata
        self.throbber = LoadingAnimation(40, clutter.Color(255,255,255,255), clutter.Color(128,128,128,128))
        self.throbber.set_position(self.ui.x(0.5), self.ui.y(0.5))
        self.throbber.show()
        self.group.add(self.throbber)
        
        # Create and initialize screen items
        gobject.timeout_add(500, self._get_disc_information)

        self.group.show()
        ui.getStage().add(self.group)

    def _get_disc_information(self):
        """
        Fetch album information from the Internet and create widgets based
        on received data.
        """
        try:
            disc = self.library.get_compact_disc_information()
        
            title = disc.get_title()
            artist = disc.get_artist()
            tracks = disc.get_tracks()

            self.playlist = Playlist(tracks)
            self._create_album_info(title, artist, tracks, disc.get_length())
            self._create_track_menu(tracks)
            self._create_album_cover_texture(artist, title)
            self._create_list_indicator()
            
            # Check if artfile exists. If it doesn't let's make a search for it.
            art_path = os.path.expanduser('~/.entertainer/cache/album_art')
            art_file = os.path.join(art_path, artist + " - " + title + ".jpg")
            if artist != "Unknown artist" and not os.path.exists(art_file):
                art_search = AlbumArtDownloader(title, artist, art_path, self._update_albumart)
                art_search.start()
            
        except: # No disc in drive
            no_disc = clutter.Label()
            no_disc.set_font_name(self.theme.getFont() + ' 32px')
            no_disc.set_color(self.theme.getColor("title"))
            no_disc.set_text("No audio disc in drive")
            no_disc.set_anchor_point_from_gravity(clutter.GRAVITY_CENTER)
            no_disc.set_position(self.ui.x(0.5), self.ui.y(0.5))
            no_disc.show()
            self.group.add(no_disc)
        
        # Remove loading animation
        self.throbber.hide()
        self.group.remove(self.throbber)
        del self.throbber
        
        return False # This function should be called only once (gobject timeout)
    
    def _update_albumart(self, artist, title):
        """
        Search album art for current audio disc. This function is called only
        if album art doesn't exists already. If album art is found then we replace
        current disc icon with the new album art.
        @param artist: Artist name
        @param title: Album title
        """
        art_path = os.path.expanduser('~/.entertainer/cache/album_art')
        art_file = os.path.join(art_path, artist + " - " + title + ".jpg")
        
        if os.path.exists(art_file):
            self.art2 = clutter.Texture()
            tmp = gtk.gdk.pixbuf_new_from_file(art_file)

            clutter.threads_enter()
            self.art2.set_pixbuf(tmp)
            clutter.threads_leave()

            self.art2.set_position(self.ui.x(0.1),self.ui.y(0.165))
            self.art2.set_size(self.ui.x(0.3148), self.ui.y(0.5599))
            self.art2.set_opacity(0)
            self.art2.show()
            self.group.add(self.art2)

            self.timeline_in = clutter.Timeline(35, 26)
            self.alpha_in = clutter.Alpha(self.timeline_in, clutter.smoothstep_inc_func)
            self.in_behaviour = clutter.BehaviourOpacity(0, 255, self.alpha_in)
            self.in_behaviour.apply(self.art2)

            self.timeline_out = clutter.Timeline(35, 26)
            self.alpha_out = clutter.Alpha(self.timeline_out, clutter.smoothstep_inc_func)
            self.out_behaviour = clutter.BehaviourOpacity(255, 0, self.alpha_out)
            self.out_behaviour.apply(self.art)

            
            self.timeline_out.start()
            self.timeline_in.start()
        
    def _create_album_cover_texture(self, artist, title):
        """
        Create a texture that is displayed next to track list. This texture
        displays album cover art.
        @param artist: Artist
        @param title: Title of the album
        """
        path = os.path.expanduser('~/.entertainer/cache/album_art')
        coverfile = os.path.join(path, artist + " - " + title + ".jpg")
        
        if(os.path.exists(coverfile)):
            pixbuf = gtk.gdk.pixbuf_new_from_file(coverfile)
        else:
            pixbuf = gtk.gdk.pixbuf_new_from_file(self.theme.getImage("disc"))
        self.art = EyeCandyTexture(pixbuf, self.ui.x(0.3148), self.ui.y(0.5599))
        self.art.set_position(self.ui.x(0.1),self.ui.y(0.13))
        self.art.show()
        self.art.set_rotation(clutter.Y_AXIS, 25, 0, 0, 0)
        self.group.add(self.art)

    def _create_album_info(self, title, artist_name, tracks, length):
        """
        Create album info labels.
        @param title: Album title
        @param artist_name: Artist
        @param tracks: List of CompactDisc objects
        """
        album = clutter.Label()
        album.set_font_name(self.theme.getFont() + " bold " + str(self.ui.y(0.04167)) + "px")
        album.set_color(self.theme.getColor("text"))
        album.set_text(artist_name + " - " + title)
        album.set_size(self.ui.x(0.4393), self.ui.y(0.06510))
        album.set_line_wrap(False)
        album.set_ellipsize(pango.ELLIPSIZE_END)
        album.set_position(self.ui.x(0.50146), self.ui.y(0.13))
        album.show()
        self.group.add(album)

        minutes = str(length / 60)
        num_of_tracks = clutter.Label()
        num_of_tracks.set_font_name(self.theme.getFont() + " bold " + str(self.ui.y(0.02604)) + "px")
        num_of_tracks.set_color(self.theme.getColor("subtitle"))
        num_of_tracks.set_text(str(len(tracks)) + " tracks, " + minutes + " minutes")
        num_of_tracks.set_size(self.ui.x(0.366), self.ui.y(0.06510))
        num_of_tracks.set_position(self.ui.x(0.50146), self.ui.y(0.18))
        num_of_tracks.show()
        self.group.add(num_of_tracks)

    def _create_track_menu(self, tracks):
        """
        Create a track menu. This menu contains list of all tracks on album.
        @param tracks: List of CompactDisc objects
        """
        self.track_menu = TextMenu(self.theme, 
                                   self.frontend.get_configuration().show_effects())
        self.track_menu.set_row_count(1)
        self.track_menu.set_visible_column_count(7)
        self.track_menu.set_item_size(self.ui.x(0.4393), self.ui.y(0.0781))
        self.track_menu.set_position(self.ui.x(0.4978), self.ui.y(0.2344))

        for index, track in enumerate(tracks):
            length = str(track.get_length() / 60) + ":" + str(track.get_length() % 60).zfill(2)
            item = TextMenuItem(self.ui.x(0.4393), self.ui.y(0.0781), self.theme, track.get_title(), length)
            item.set_userdata(index)
            self.track_menu.add_actor(item)
        self.track_menu.show()
        self.track_menu.set_active(True)
        self.group.add(self.track_menu)
    
    def _create_list_indicator(self):
        """
        Create list indicator widget
        """
        self.li = ListIndicator(self.ui.x(0.0878), self.ui.y(0.04427), self.theme, ListIndicator.VERTICAL)
        self.li.set_position(self.ui - self.li.get_width() -self.ui.x(0.06589),
                             self.ui.STAGE_HEIGHT - self.ui.y(0.1953))
        self.li.set_delimiter(" | ")
        self.li.show()
        self.li.set_maximum(self.track_menu.get_number_of_items())
        self.li.set_current(1)
        self.group.add(self.li)
    
    def get_group(self):
        """
        Get all actors of the screen.
        @return clutter.Group 
        """
        return self.group

    def get_type(self):
        """Return screen type."""
        return Screen.NORMAL
    
    def get_name(self):
        """Return screen name (human readable)"""
        return "DiscScreen"
    
    def handle_user_event(self, event):   
        """ 
        Handle screen specific user events
        @param event: UserEvent object
        """
        type = event.get_type()
        
        if type == UserEvent.NAVIGATE_UP:
            self.track_menu.move(TextMenu.UP)
            self.li.set_current(self.track_menu.get_current_postition() + 1)
        
        elif type == UserEvent.NAVIGATE_DOWN:
            self.track_menu.move(TextMenu.DOWN)
            self.li.set_current(self.track_menu.get_current_postition() + 1)
        
        elif type == UserEvent.NAVIGATE_LEFT:
            pass
        
        elif type == UserEvent.NAVIGATE_RIGHT:
            pass
        
        elif type == UserEvent.NAVIGATE_SELECT:
            track_index = self.track_menu.get_current_menuitem().get_userdata()
            self.playlist.set_current(track_index)
            self.player.set_playlist(self.playlist)
            self.player.play()

